package people.paper.tv.utils.monitor;

import android.os.Handler;
import android.os.HandlerThread;
import android.os.SystemClock;
import android.text.TextUtils;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;

import java.io.Serializable;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

public class HttpMonitor {
    private static Handler handler;
    private static final String MONITOR_URL = "http://cl-dl.cc0808.com/dl/cdn/errorinfo";
    private static final OkHttpClient CLIENT = new OkHttpClient.Builder()
            .connectTimeout(10, TimeUnit.SECONDS)
            .readTimeout(10, TimeUnit.SECONDS)
            .writeTimeout(10, TimeUnit.SECONDS)
            .build();

    private static final Map<String, Long> URLS = new HashMap<>();

    static {
        HandlerThread handlerThread = new HandlerThread("HttpMonitor-thread");
        handlerThread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread thread, Throwable throwable) {
                throwable.printStackTrace();
            }
        });
        handlerThread.start();
        handler = new Handler(handlerThread.getLooper());
    }

    public static class HttpMonitorBean implements Serializable {
        public static final HttpMonitorBean create(String url) {
            HttpMonitorBean bean = new HttpMonitorBean();
            bean.url = url;
            return bean;
        }

        @JSONField(serialize = false)
        private String id = null;

        private String url;
        private Map<String, String> headers = new HashMap<>();

        public HttpMonitorBean withHeader(String key, String value) {
            synchronized (headers) {
                headers.put(key, value);
                id = null;
            }
            return this;
        }

        public HttpMonitorBean withHeaders(Map<String, String> _headers) {
            synchronized (headers) {
                headers.putAll(_headers);
                id = null;
            }
            return this;
        }

        public String getId() {
            synchronized (headers) {
                if (id == null)
                    id = calculateMD5(JSONObject.toJSONString(this));
                return id;
            }
        }

        public String getHeadersJsonString() {
            synchronized (headers) {
                return JSONObject.toJSONString(headers);
            }
        }
    }

    public static final void start(HttpMonitorBean bean) {
        synchronized (URLS) {
            String id = bean.getId();
            if (!URLS.containsKey(id))
                URLS.put(id, SystemClock.uptimeMillis());
        }
    }

    public static final void end(HttpMonitorBean bean,
                                 int httpCode,
                                 int errCode,
                                 String errMsg) {
        synchronized (URLS) {
            String id = bean.getId();
            if (URLS.containsKey(id)) {
                long duration = SystemClock.uptimeMillis() - URLS.get(id);
                URLS.remove(id);
                execute(bean, httpCode, errCode, errMsg, duration);
            }
        }
    }

    private static final void execute(final HttpMonitorBean bean, final int httpCode, final int errCode, final String errMsg, final long duration) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                String params = bean.getHeadersJsonString();
                Request request = new Request.Builder()
                        .get()
                        .url(MONITOR_URL)
                        .addHeader("m_method", bean.url)
                        .addHeader("m_params", TextUtils.isEmpty(params) ? "" : params)
                        .addHeader("code", String.valueOf(httpCode))
                        .addHeader("m_errcode", String.valueOf(errCode))
                        .addHeader("m_errmsg", TextUtils.isEmpty(errMsg) ? "" : errMsg)
                        .addHeader("m_duration", String.valueOf(duration))
                        .build();
                try {
                    Response response = CLIENT.newCall(request).execute();
                    int code = response.code();
                    if (!(code >= 200 && code < 400)) {
                        handler.postDelayed(this, 30 * 1000);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private static String calculateMD5(String string) {
        if (TextUtils.isEmpty(string)) {
            return "";
        }
        MessageDigest md5 = null;
        try {
            md5 = MessageDigest.getInstance("MD5");
            byte[] bytes = md5.digest(string.getBytes());
            String result = "";
            for (byte b : bytes) {
                String temp = Integer.toHexString(b & 0xff);
                if (temp.length() == 1) {
                    temp = "0" + temp;
                }
                result += temp;
            }
            return result;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return "";
    }
}
